/* Copyright (c) 2016-2018, NVIDIA CORPORATION.  All rights reserved.
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/delay.h>
#include "nvi.h"
#include "nvi_dmp_mpu.h"

#define NVI_6QUAT_EN			(1)

#define MPU_DMP_PERIOD_US		(5000)
#define DMP_HDR_LEN_MAX			(4)
#define DMP_DEV_ABLE_LEN		(2)
#define AUX_PORT_DEV_GMF		(0)
#define MSK_AUX_PORTS_DEV_GMF		(0x3)
#define AUX_PORT_DEV_PRS		(2)
/* The MPU DMP FW requires port 0 to be enabled and reading 10 bytes
 * when pressure is enabled.  This is accomplished by enabling the
 * compass with the pressure dependency mask, MSK_AUX_PORTS_DEV_PRS.
 */
#define MSK_AUX_PORTS_DEV_PRS		(0xF)
#define MSK_EN_AUX_PORTS		(((1 << (AUX_PORT_IO + DEV_N_AUX)) - \
					  1) & ~MSK_DEV_SNSR)

static struct nvi_aux_port_dmp_dev ap_dd_gmf[] = {
	{
		.dev			= COMPASS_ID_AK8963,
		.dmp_rd_len_sts		= 0,
		.dmp_rd_len_data	= 6,
		.dmp_rd_be_sts		= true,
		.dmp_rd_be_data		= false,
		.dmp_rd_ctrl		= 0x0A,
		.dmp_rd_reg		= 0x01,
	},
	{
		.dev			= COMPASS_ID_AK8975,
		.dmp_rd_len_sts		= 0,
		.dmp_rd_len_data	= 6,
		.dmp_rd_be_sts		= true,
		.dmp_rd_be_data		= false,
		.dmp_rd_ctrl		= 0x0A,
		.dmp_rd_reg		= 0x01,
	},
	{
		.dev			= COMPASS_ID_AK09911,
		.dmp_rd_len_sts		= 0,
		.dmp_rd_len_data	= 6,
		.dmp_rd_be_sts		= true,
		.dmp_rd_be_data		= false,
		.dmp_rd_ctrl		= 0x0A,
		.dmp_rd_reg		= 0x10,
	},
};

static struct nvi_aux_port_dmp_dev ap_dd_prs[] = {
	{
		.dev			= PRESSURE_ID_BMP280,
		.dmp_rd_len_sts		= 0,
		.dmp_rd_len_data	= 6,
		.dmp_rd_be_sts		= true,
		.dmp_rd_be_data		= true,
		.dmp_rd_ctrl		= 0x06,
		.dmp_rd_reg		= 0xF7,
	},
};

static struct nvi_dmp_aux_port nvi_dmp_ap[] = {
	/* MPU DMP FW supports only this configuration */
	/* port 0 */
	{
		.type			= SECONDARY_SLAVE_TYPE_COMPASS,
		.port_rd		= true,
		.port			= AUX_PORT_DEV_GMF,
		.dd_n			= ARRAY_SIZE(ap_dd_gmf),
		.dd			= ap_dd_gmf,
	},
	/* port 1 */
	{
		.type			= SECONDARY_SLAVE_TYPE_COMPASS,
		.port_rd		= false,
		.port			= AUX_PORT_DEV_GMF + 1,
	},
	/* port 2 */
	{
		.type			= SECONDARY_SLAVE_TYPE_PRESSURE,
		.port_rd		= true,
		.port			= AUX_PORT_DEV_PRS,
		.dd_n			= ARRAY_SIZE(ap_dd_prs),
		.dd			= ap_dd_prs,
	},
	/* port 3 */
	{
		.type			= SECONDARY_SLAVE_TYPE_PRESSURE,
		.port_rd		= false,
		.port			= AUX_PORT_DEV_PRS + 1,
	},
};

struct nvi_dmp_dev {
	unsigned int dev;
	unsigned int aux_port;
	unsigned int depend_msk;	/* sensor dependencies */
	unsigned int buf_n;
	u16 en_addr;
	u8 en_len;
	u8 en[DMP_DEV_ABLE_LEN];
	u8 dis[DMP_DEV_ABLE_LEN];
	u16 odr_cfg;
	u16 odr_cntr;
	int (*fn_init)(struct nvi_state *st, unsigned int *en_msk);
};

struct nvi_dmp_hdr {
	unsigned int dev;
	unsigned int aux_port;
	unsigned int buf_n;
	unsigned int hdr_n;
	u8 hdr[DMP_HDR_LEN_MAX];
	u8 hdr_msk[DMP_HDR_LEN_MAX];
};


static int nvi_dmp_sm_init(struct nvi_state *st, unsigned int *en_msk)
{
	int ret;

	ret = nvi_mem_wr_be_mc(st, D_SMD_MOT_THLD, 4,
			       st->snsr[DEV_SM].cfg.thresh_lo << 16,
			       &st->mc.mpu.d_smd_mot_thld);
	ret |= nvi_mem_wr_be_mc(st, D_SMD_DELAY_CNTR, 4,
				st->snsr[DEV_SM].cfg.thresh_hi,
				&st->mc.mpu.d_smd_delay_cntr);
	ret |= nvi_mem_wr_be_mc(st, D_SMD_DELAY_THLD, 4,
				st->snsr[DEV_SM].cfg.delay_us_min,
				&st->mc.mpu.d_smd_delay_thld);
	ret |= nvi_mem_wr_be_mc(st, D_SMD_DELAY2_THLD, 4,
				st->snsr[DEV_SM].cfg.delay_us_max,
				&st->mc.mpu.d_smd_delay2_thld);
	ret |= nvi_mem_wr_be_mc(st, D_SMD_EXE_STATE, 4,
				st->snsr[DEV_SM].cfg.report_n,
				&st->mc.mpu.d_smd_exe_state);
	return ret;
}

static struct nvi_dmp_dev nvi_dmp_devs[] = {
	{
		.dev			= DEV_ACC,
		.buf_n			= 6,
		.en_addr		= CFG_OUT_ACCL,
		.en_len			= 2,
		.en			= { 0xA3, 0xA3 },
		.dis			= { 0xF4, 0x12 },
		.odr_cfg		= KEY_CFG_ACCL_ODR,
		.odr_cntr		= KEY_ODR_CNTR_ACCL,
	},
	{
		.dev			= DEV_GYR,
		.buf_n			= 6,
		.en_addr		= CFG_OUT_GYRO,
		.en_len			= 2,
		.en			= { 0xA3, 0xA3 },
		.dis			= { 0xF4, 0x12 },
		.odr_cfg		= KEY_CFG_GYRO_ODR,
		.odr_cntr		= KEY_ODR_CNTR_GYRO,
	},
#if NVI_6QUAT_EN
	{
		.dev			= DEV_QTN,
		.depend_msk		= (1 << DEV_ACC) |
					  (1 << DEV_GYR),
		.buf_n			= 12,
		.en_addr		= CFG_OUT_6QUAT,
		.en_len			= 2,
		.en			= { 0xA3, 0xA3 },
		.dis			= { 0xF4, 0x13 },
		.odr_cfg		= KEY_CFG_6QUAT_ODR,
		.odr_cntr		= KEY_ODR_CNTR_6QUAT,
	},
#else /* !NVI_6QUAT_EN */
	{
		.dev			= DEV_QTN,
		.depend_msk		= (1 << DEV_ACC) |
					  (1 << DEV_GYR),
		.buf_n			= 12,
		.en_addr		= CFG_OUT_3QUAT,
		.en_len			= 2,
		.en			= { 0xA3, 0xA3 },
		.dis			= { 0xF4, 0x13 },
		.odr_cfg		= KEY_CFG_3QUAT_ODR,
		.odr_cntr		= KEY_ODR_CNTR_3QUAT,
	},
#endif /* NVI_6QUAT_EN */
	{
		.dev			= DEV_SM,
		.depend_msk		= (1 << DEV_ACC),
		.buf_n			= 1,
		.fn_init		= &nvi_dmp_sm_init,
		.en_addr		= D_SMD_ENABLE,
		.en_len			= 2,
		.en			= { 0x00, 0x01 },
		.dis			= { 0x00, 0x00 },
	},
	{
		.dev			= DEV_AUX,
		.aux_port		= AUX_PORT_DEV_GMF,
		.depend_msk		= (MSK_AUX_PORTS_DEV_GMF << DEV_N_AUX),
		.buf_n			= 6,
		.en_addr		= CFG_OUT_CPASS,
		.en_len			= 2,
		.en			= { 0xA3, 0xA3 },
		.dis			= { 0xF4, 0x12 },
		.odr_cfg		= KEY_CFG_CPASS_ODR,
		.odr_cntr		= KEY_ODR_CNTR_CPASS,
	},
	{
		.dev			= DEV_AUX,
		.aux_port		= AUX_PORT_DEV_PRS,
		.depend_msk		= (MSK_AUX_PORTS_DEV_PRS << DEV_N_AUX),
		.buf_n			= 6,
		.en_addr		= CFG_OUT_PRESS,
		.en_len			= 2,
		.en			= { 0xA3, 0xA3 },
		.dis			= { 0xF4, 0x12 },
		.odr_cfg		= KEY_CFG_PRESS_ODR,
		.odr_cntr		= KEY_ODR_CNTR_PRESS,
	},
};

static struct nvi_dmp_hdr nvi_dmp_hdrs[] = {
	{
		.dev			= DEV_ACC,
		.buf_n			= 6,
		.hdr_n			= 2,
		.hdr			= { 0x40, 0x00 },
		.hdr_msk		= { 0xFF, 0xF0 },
	},
	{
		.dev			= DEV_GYR,
		.buf_n			= 6,
		.hdr_n			= 2,
		.hdr			= { 0x20, 0x00 },
		.hdr_msk		= { 0xFF, 0xF0 },
	},
	{
		.dev			= DEV_QTN, /* 3QUAT */
		.buf_n			= 12,
		.hdr_n			= 4,
		.hdr			= { 0x08, 0x00, 0x08, 0x00 },
		.hdr_msk		= { 0xFF, 0xF0, 0xFF, 0xF0 },
	},
	{
		.dev			= DEV_QTN, /* 6QUAT */
		.buf_n			= 12,
		.hdr_n			= 4,
		.hdr			= { 0x04, 0x00, 0x04, 0x00 },
		.hdr_msk		= { 0xFF, 0xF0, 0xFF, 0xF0 },
	},
	{
		.dev			= DEV_SM,
		.buf_n			= 1,
		.hdr_n			= 0,
	},
	{
		.dev			= DEV_AUX, /* GMF */
		.aux_port		= AUX_PORT_DEV_GMF,
		.buf_n			= 6,
		.hdr_n			= 2,
		.hdr			= { 0x10, 0x00 },
		.hdr_msk		= { 0xFF, 0xF0 },
	},
	{
		.dev			= DEV_AUX, /* PRS */
		.aux_port		= AUX_PORT_DEV_PRS,
		.buf_n			= 6,
		.hdr_n			= 2,
		.hdr			= { 0x80, 0x00 },
		.hdr_msk		= { 0xFF, 0xF0 },
	},
	{
		.dev			= DEV_STP,
		.buf_n			= 6,
		.hdr_n			= 2,
		.hdr			= { 0x01, 0x00 },
		.hdr_msk		= { 0xFF, 0xF0 },
	},
	{
		.dev			= -1, /* PQUAT */
		.buf_n			= 6,
		.hdr_n			= 2,
		.hdr			= { 0x02, 0x00 },
		.hdr_msk		= { 0xFF, 0xF0 },
	},
};

static unsigned int nvi_dmp_dbg(struct nvi_state *st, unsigned int n)
{
	dev_info(&st->i2c->dev,
		 "n=%04u %02x %02x %02x %02x %02x %02x %02x %02x\n",
		 n, st->buf[st->buf_i], st->buf[st->buf_i + 1],
		 st->buf[st->buf_i + 2], st->buf[st->buf_i + 3],
		 st->buf[st->buf_i + 4], st->buf[st->buf_i + 5],
		 st->buf[st->buf_i + 6], st->buf[st->buf_i + 7]);
	dev_info(&st->i2c->dev,
		 "       %02x %02x %02x %02x %02x %02x %02x %02x\n",
		 st->buf[st->buf_i + 8], st->buf[st->buf_i + 9],
		 st->buf[st->buf_i + 10], st->buf[st->buf_i + 11],
		 st->buf[st->buf_i + 12], st->buf[st->buf_i + 13],
		 st->buf[st->buf_i + 14], st->buf[st->buf_i + 15]);
	if (n > 16) {
		st->buf_i += 16;
		n -= 16;
	} else {
		st->buf_i += n;
		n = 0;
	}
	return n;
}

static void nvi_dmp_rd_aux(struct nvi_state *st, struct nvi_dmp_hdr *dh,
			   unsigned int buf_i, s64 ts)
{
	struct aux_port *ap;

	if (dh->aux_port >= AUX_PORT_IO)
		return;

	if (!(st->snsr[DEV_AUX].enable & (1 << dh->aux_port)))
		return;

	ap = &st->aux.port[dh->aux_port];
	ap->nmp.handler(&st->buf[buf_i], dh->buf_n,
			nvi_ts_dev(st, ts, dh->dev, dh->aux_port),
			ap->nmp.ext_driver);
}

static int nvi_dmp_rd(struct nvi_state *st, s64 ts, unsigned int n)
{
	struct nvi_dmp_hdr *dh;
	unsigned int dh_i;
	unsigned int i;
	u8 byte;

	while (n > DMP_HDR_LEN_MAX) {
		if (st->sts & NVI_DBG_SPEW_FIFO) {
			n = nvi_dmp_dbg(st, n);
			continue;
		}

		if (st->sts & (NVS_STS_SUSPEND | NVS_STS_SHUTDOWN))
			return -1;

		for (dh_i = 0; dh_i < ARRAY_SIZE(nvi_dmp_hdrs); dh_i++) {
			dh = &nvi_dmp_hdrs[dh_i];
			if (!dh->hdr_n)
				continue;

			for (i = 0; i < dh->hdr_n; i++) {
				byte = st->buf[st->buf_i + i];
				byte &= dh->hdr_msk[i];
				if (byte != dh->hdr[i])
					break;
			}
			if (i >= dh->hdr_n)
				break;
		}
		if (dh_i >= ARRAY_SIZE(nvi_dmp_hdrs)) {
			/* unknown header: lost DMP sync so DMP reset */
			if (st->sts & NVI_DBG_SPEW_MSG)
				dev_err(&st->i2c->dev,
					"%s ERR: DMP sync  HDR: %x %x %x %x\n",
					__func__, st->buf[st->buf_i],
					st->buf[st->buf_i + 1],
					st->buf[st->buf_i + 2],
					st->buf[st->buf_i + 3]);
			nvi_err(st);
			return -1;
		}

		if (n > dh->buf_n + i) {
			if (dh->dev == DEV_AUX)
				nvi_dmp_rd_aux(st, dh, st->buf_i + i, ts);
			else if (dh->dev < DEV_N)
				nvi_push(st, dh->dev, &st->buf[st->buf_i + i],
					 nvi_ts_dev(st, ts, dh->dev, 0));
			i += dh->buf_n;
			st->buf_i += i;
			n -= i;
		} else {
			return 0;
		}
	}

	return 0;
}

static int nvi_dmp_clk_n(struct nvi_state *st, u32 *clk_n)
{
	return nvi_mem_rd_le(st, D_DMP_RUN_CNTR, 4, clk_n);
}

static int nvi_dmp_irq(struct nvi_state *st, unsigned int en_msk)
{
	u32 able;

	if ((en_msk & MSK_DEV_ALL) & ~((1 << DEV_SM) | (1 << DEV_STP)))
		/* DMP requires FIFO IRQ */
		able = 0xFE;
	else
		/* DMP IRQ is in event mode */
		able = 0xA3;
	return nvi_mem_wr_be_mc(st, CFG_FIFO_INT, 1, able,
				&st->mc.mpu.cfg_fifo_int);
}

static int nvi_dd_odr(struct nvi_state *st, struct nvi_dmp_dev *dd)
{
	u16 odr_cfg;
	unsigned int period_us;
	int ret;

	if (!(dd->odr_cfg | dd->odr_cntr))
		return 0;

	if (dd->dev == DEV_AUX)
		period_us = st->aux.port[dd->aux_port].period_us_req;
	else
		period_us = st->snsr[dd->dev].period_us_req;
	if (period_us) {
		odr_cfg = period_us / MPU_DMP_PERIOD_US;
		period_us = MPU_DMP_PERIOD_US;
		if (odr_cfg) {
			period_us *= odr_cfg;
			odr_cfg--;
		}
	} else {
		period_us = MPU_DMP_PERIOD_US;
		odr_cfg = 0;
	}
	if (dd->dev == DEV_AUX) {
		st->aux.port[dd->aux_port].odr = odr_cfg;
		st->aux.port[dd->aux_port].period_us_rd = period_us;
	} else {
		st->snsr[dd->dev].odr = odr_cfg;
		st->snsr[dd->dev].period_us_rd = period_us;
	}
	ret = nvi_mem_wr_be(st, dd->odr_cntr, 2, 0);
	ret |= nvi_mem_wr_be(st, dd->odr_cfg, 2, odr_cfg);
	ret |= nvi_mem_wr_be(st, dd->odr_cntr, 2, 0);
	return ret;
}

static int nvi_dd_able(struct nvi_state *st, struct nvi_dmp_dev *dd,
		       unsigned int *en_msk)
{
	bool en = false;
	int ret = 0;

	if (dd->dev == DEV_AUX) {
		if (*en_msk & (1 << (dd->aux_port + DEV_N_AUX)))
			en = true;
	} else if (dd->dev < DEV_AUX) {
		if (*en_msk & (1 << dd->dev))
			en = true;
	} else {
		return 0;
	}

	if (en) {
		if (dd->fn_init) {
			ret = dd->fn_init(st, en_msk);
			if (ret < 0)
				return ret;

			if (ret > 0)
				/* disable without error */
				en = false;
		}
	}

	if (en) {
		ret = nvi_dd_odr(st, dd);
		ret |= nvi_mem_wr(st, dd->en_addr, dd->en_len, dd->en, false);
		if (ret)
			en = false;
	}
	if (!en)
		nvi_mem_wr(st, dd->en_addr, dd->en_len, dd->dis, false);
	if (en)
		st->snsr[dd->dev].buf_n = dd->buf_n;
	else if (dd->dev == DEV_AUX)
		*en_msk &= ~(dd->depend_msk & MSK_EN_AUX_PORTS);
	else
		*en_msk &= ~(1 << dd->dev);
	return ret;
}

static struct nvi_dmp_dev *nvi_dd(struct nvi_state *st,
				  unsigned int dev, int port)
{
	unsigned int i;

	for (i = 0; i < ARRAY_SIZE(nvi_dmp_devs); i++) {
		if (dev == nvi_dmp_devs[i].dev) {
			if (dev == DEV_AUX) {
				if (port != nvi_dmp_devs[i].aux_port)
					continue;
			}
			return &nvi_dmp_devs[i];
		}
	}

	return NULL;
}

static int nvi_dd_batch(struct nvi_state *st, unsigned int dev, int port)
{
	struct nvi_dmp_dev *dd;

	dd = nvi_dd(st, dev, port);
	if (dd == NULL)
		return -EINVAL;

	return nvi_dd_odr(st, dd);
}

static int nvi_dd_init(struct nvi_state *st, unsigned int dev)
{
	struct nvi_dmp_dev *dd;
	unsigned int en_msk = st->en_msk & MSK_DEV_SNSR;
	int ret = -EINVAL;

	dd = nvi_dd(st, dev, -1);
	if (dd == NULL)
		return -EINVAL;

	if (dd->fn_init)
		ret = dd->fn_init(st, &en_msk);
	return ret;
}


static u8 nvi_dmp_fcfg_gyro_a[8][3] = {
	{ 0x4C, 0xCD, 0x6C },
	{ 0xCD, 0x4C, 0x6C },
	{ 0x4C, 0xCD, 0x6C },
	{ 0xCD, 0x4C, 0x6C },
	{ 0x4C, 0xCD, 0x6C },
	{ 0xCD, 0x4C, 0x6C },
	{ 0x4C, 0xCD, 0x6C },
	{ 0xCD, 0x4C, 0x6C },
};

static u8 nvi_dmp_fcfg_gyro_b[8][3] = {
	{ 0x36, 0x56, 0x76 },
	{ 0x36, 0x57, 0x76 },
	{ 0x37, 0x57, 0x76 },
	{ 0x37, 0x56, 0x76 },
	{ 0x37, 0x56, 0x77 },
	{ 0x37, 0x56, 0x77 },
	{ 0x36, 0x57, 0x77 },
	{ 0x36, 0x56, 0x77 },
};

static u8 nvi_dmp_fcfg_accl_a[8][3] = {
	{ 0x0C, 0xC9, 0x2C },
	{ 0xC9, 0x0C, 0x2C },
	{ 0x0C, 0xC9, 0x2C },
	{ 0xC9, 0x0C, 0x2C },
	{ 0x0C, 0xC9, 0x2C },
	{ 0xC9, 0x0C, 0x2C },
	{ 0x0C, 0xC9, 0x2C },
	{ 0xC9, 0x0C, 0x2C },
};

static u8 nvi_dmp_fcfg_accl_b[8][3] = {
	{ 0x26, 0x46, 0x66 },
	{ 0x26, 0x47, 0x66 },
	{ 0x27, 0x47, 0x66 },
	{ 0x27, 0x46, 0x66 },
	{ 0x27, 0x46, 0x67 },
	{ 0x27, 0x46, 0x66 },
	{ 0x26, 0x47, 0x67 },
	{ 0x26, 0x46, 0x67 },
};

static signed char nvi_matrix[8][9] = {
	{  1,  0,  0,  0,  1,  0,  0,  0,  1 },
	{  0,  1,  0, -1,  0,  0,  0,  0,  1 },
	{ -1,  0,  0,  0, -1,  0,  0,  0,  1 },
	{  0, -1,  0,  1,  0,  0,  0,  0,  1 },
	{ -1,  0,  0,  0,  1,  0,  0,  0, -1 },
	{  0, -1,  0,  1,  0,  0,  0,  0, -1 },
	{  1,  0,  0,  0, -1,  0,  0,  0, -1 },
	{  0,  1,  0,  1,  0,  0,  0,  0, -1 },
};

static int nvi_dmp_matrix_i(signed char *matrix)
{
	int i;
	int j;

	for (i = 0; i < 8; i++) {
		for (j = 0; j < 9; j++) {
			if (matrix[j] != nvi_matrix[i][j])
				break;
		}
		if (j >= 9)
			return i;
	}

	pr_err("%s ERR: matrix=%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
	       __func__, matrix[0], matrix[1], matrix[2], matrix[3],
	       matrix[4], matrix[5], matrix[6], matrix[7], matrix[8]);
	return -EINVAL;
}

static int nvi_dmp_init(struct nvi_state *st)
{
	int i;
	int ret;

	memset(&st->mc, 0, sizeof(st->mc));
	i = nvi_dmp_matrix_i(st->snsr[DEV_GYR].cfg.matrix);
	if (i < 0)
		return -EINVAL;

	ret = nvi_mem_wr(st, FCFG_1, 3, &nvi_dmp_fcfg_gyro_a[i][0], false);
	ret |= nvi_mem_wr(st, FCFG_3, 3, &nvi_dmp_fcfg_gyro_b[i][0], false);
	i = nvi_dmp_matrix_i(st->snsr[DEV_ACC].cfg.matrix);
	if (i < 0)
		return -EINVAL;

	ret |= nvi_mem_wr(st, FCFG_2, 3, &nvi_dmp_fcfg_accl_a[i][0], false);
	ret |= nvi_mem_wr(st, FCFG_7, 3, &nvi_dmp_fcfg_accl_b[i][0], false);
	ret |= nvi_pm_wr(st, __func__, INV_CLK_PLL, 0, 0);
	st->en_msk |= (1 << DEV_DMP);
	ret |= nvi_user_ctrl_en(st, __func__, true, false, false, false);
	st->en_msk &= ~(1 << DEV_DMP);
	if (ret)
		return ret;

	msleep(400);
	return nvi_user_ctrl_en(st, __func__, false, false, false, false);
}

static int nvi_dmp_en(struct nvi_state *st)
{
	struct nvi_dmp_dev *dd;
	unsigned int i;
	unsigned int irq_msk = 0;
	unsigned int en_msk = 0;
	int ret = 0;

	st->en_msk |= (1 << DEV_DMP);
	for (i = 0; i < ARRAY_SIZE(nvi_dmp_devs); i++) {
		dd = &nvi_dmp_devs[i];
		if (dd->dev == DEV_AUX) {
			if (st->snsr[DEV_AUX].enable & (1 << dd->aux_port)) {
				irq_msk |= (1 << DEV_AUX);
				en_msk |= (1 << DEV_AUX);
				en_msk |= (1 << (dd->aux_port + DEV_N_AUX));
				en_msk |= dd->depend_msk;
			}
		} else if (dd->dev < DEV_AUX) {
			if (st->snsr[dd->dev].enable) {
				irq_msk |= (1 << dd->dev);
				en_msk |= (1 << dd->dev);
				en_msk |= dd->depend_msk;
			}
		}
	}

	st->src[SRC_DMP].period_us_src = MPU_DMP_PERIOD_US;
	st->src[SRC_MPU].period_us_src = MPU_DMP_PERIOD_US;
	ret |= nvi_i2c_wr_rc(st, &st->hal->reg->gyro_config1, 0x03,
			     __func__, &st->rc.gyro_config1);
	ret |= nvi_i2c_wr_rc(st, &st->hal->reg->gyro_config2, 0x18,
			     __func__, &st->rc.gyro_config2);
	ret |= nvi_i2c_wr_rc(st, &st->hal->reg->accel_config, 0,
			     __func__, &st->rc.accel_config);
	ret |= nvi_i2c_wr_rc(st, &st->hal->reg->smplrt[0], 0x04,
			     __func__, (u8 *)&st->rc.smplrt[0]);
	if (ret)
		return ret;

	for (i = 0; i < ARRAY_SIZE(nvi_dmp_devs); i++)
		ret |= nvi_dd_able(st, &nvi_dmp_devs[i], &en_msk);
	if (ret)
		return ret;

	st->aux.dmp_en_msk = en_msk >> DEV_N_AUX;
	if (st->aux.dmp_en_msk) {
		ret = nvi_aux_enable(st, __func__, true, true);
		if (ret)
			return ret;
	}
	ret = nvi_aux_delay(st, __func__);
	ret |= nvi_dmp_irq(st, irq_msk & en_msk);
	if (!ret) {
		st->en_msk |= (en_msk & ((1 << DEV_N_AUX) - 1));
		nvi_push_delay(st);
		ret = nvi_reset(st, __func__, true, false, true);
	}
	return ret;
}

static const u8 dmp_fw_6515[] = {
	/* bank 0: 0x0020 */
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x01, 0x00, 0x7D, 0x00, 0x01,
	0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
	0x00, 0x83, 0x12, 0x6F, 0xFF, 0xDF, 0x3B, 0x64,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x3E, 0x03, 0x30, 0x40, 0x00, 0x00, 0x00,
	0x02, 0xCA, 0xE3, 0x09, 0x3E, 0x80, 0x00, 0x00,
	0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x40, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
	0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x6E,
	0x00, 0x00, 0x06, 0x92, 0x0A, 0x16, 0xC0, 0xDF,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
	0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07,
	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x0B, 0x2B,
	0x00, 0x00, 0x16, 0x57, 0x00, 0x00, 0x03, 0x59,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0xFA,
	0x00, 0x02, 0x6C, 0x1D, 0x00, 0x00, 0x00, 0x00,
	0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x07, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00,
	0x00, 0x09, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	/* bank 1: 0x0100 */
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x10, 0x72, 0x00, 0x00, 0x00, 0x40,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x58,
	0x05, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC8,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFF,
	0x08, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00,
	0x80, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0xB2, 0x6A, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	/* bank 2: 0x0200 */
	0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x0B, 0xEB, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14,
	0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x18, 0x85,
	0x04, 0x06, 0x31, 0x0A, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05,
	0xFF, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	/* bank 3: 0x0300 */
	0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00,
	0x00, 0x01, 0x80, 0x00, 0x00, 0x24, 0x26, 0xD3,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x07, 0x00, 0x10, 0x00, 0x96, 0x00, 0x3C,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x0C, 0x0A, 0x4E, 0x68, 0xCD, 0xCF, 0x77, 0x09,
	0x50, 0x16, 0x67, 0x59, 0xC6, 0x19, 0xCE, 0x82,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3C,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x02, 0x03, 0x18, 0x85, 0x00, 0x00, 0x40, 0x00,
	0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x67, 0x7D, 0xDF, 0x7E,
	0x72, 0x90, 0x2E, 0x55, 0x4C, 0xF6, 0xE6, 0x88,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	/* bank 4: 0x0400 */
	0xD8, 0xB0, 0xB5, 0xB9, 0xF3, 0xA6, 0xF8, 0xF9,
	0xD1, 0xD9, 0x81, 0x96, 0xF8, 0xF7, 0x3E, 0xD8,
	0xF3, 0xB1, 0x86, 0x96, 0xA3, 0x31, 0xD1, 0xDA,
	0xF1, 0xFF, 0xD8, 0xB3, 0xB7, 0xBB, 0x8E, 0x9E,
	0xAE, 0xF1, 0x32, 0xF5, 0x1B, 0xF1, 0xB4, 0xB8,
	0xB0, 0x80, 0x97, 0xF1, 0xA9, 0xDF, 0xDF, 0xDF,
	0xAA, 0xDF, 0xDF, 0xDF, 0xF2, 0xAA, 0xC5, 0xCD,
	0xC7, 0xA9, 0x0C, 0xC9, 0x2C, 0x97, 0xF1, 0xA9,
	0x89, 0x26, 0x46, 0x66, 0xB2, 0x89, 0x99, 0xA9,
	0x2D, 0x55, 0x7D, 0xB0, 0x8A, 0xA8, 0x96, 0x36,
	0x56, 0x76, 0xD8, 0xF1, 0xB0, 0x89, 0xB9, 0xA3,
	0xC3, 0xC5, 0xC7, 0xB1, 0x81, 0xB4, 0x97, 0xA3,
	0x11, 0xB5, 0x93, 0xA1, 0xF0, 0x24, 0x08, 0x44,
	0x10, 0x64, 0x18, 0xF1, 0x93, 0x81, 0xA3, 0x2D,
	0x55, 0x3D, 0xF2, 0xA6, 0xFA, 0xF9, 0xD1, 0xD9,
	0xF8, 0xF1, 0x83, 0xA2, 0xC3, 0xC5, 0xC7, 0xD8,
	0xF3, 0xA2, 0xDE, 0xF1, 0x82, 0x93, 0xA3, 0x2D,
	0x55, 0x7D, 0x83, 0x95, 0xF5, 0xA3, 0x30, 0xD9,
	0xF3, 0xA2, 0xF8, 0xD8, 0xF5, 0xA3, 0x50, 0xD9,
	0xF3, 0xA2, 0xF8, 0xD8, 0xF5, 0xA3, 0x70, 0xD9,
	0xF3, 0xA2, 0xF8, 0xD8, 0xF2, 0xB9, 0xA2, 0xF8,
	0xF9, 0xD1, 0xD9, 0xA6, 0xDE, 0xDF, 0xF4, 0x1C,
	0xD8, 0xF2, 0xA6, 0xF8, 0xF9, 0xD1, 0xD9, 0xF4,
	0x14, 0xD8, 0xF2, 0xF9, 0xD1, 0xD9, 0xF8, 0xF4,
	0x1E, 0xD8, 0xF2, 0xF9, 0xD1, 0xD9, 0xF8, 0xF8,
	0xF4, 0x14, 0xD8, 0xF4, 0x10, 0xD8, 0xF3, 0xA2,
	0xF8, 0xF9, 0xD1, 0xDA, 0xF2, 0xA6, 0xF8, 0xF1,
	0xA5, 0xDE, 0xD8, 0xF4, 0xA3, 0x14, 0x14, 0xD8,
	0xF1, 0xA5, 0xF8, 0xA3, 0x85, 0x95, 0x09, 0xD9,
	0xF1, 0xA5, 0xDE, 0xF2, 0xA6, 0xF8, 0xDF, 0xD8,
	0xF4, 0xA3, 0x09, 0xD8, 0xF3, 0xA2, 0xF8, 0xF9,
	0xD1, 0xF4, 0xD9, 0x08, 0x17, 0xDA, 0x42, 0xF2,
	/* bank 5: 0x0500 */
	0xA2, 0xDE, 0xF4, 0x0B, 0xD8, 0xF1, 0xA5, 0xF8,
	0xA3, 0x85, 0x95, 0x19, 0xDA, 0xF4, 0x05, 0xD8,
	0xF2, 0xA6, 0xDE, 0xDF, 0xD8, 0xF1, 0xB8, 0xAA,
	0xB3, 0x8D, 0xB4, 0x98, 0x0D, 0x35, 0x5D, 0xB2,
	0xB6, 0xBA, 0xAF, 0x8C, 0x96, 0x19, 0x8F, 0x9F,
	0xB8, 0xA8, 0x0E, 0x16, 0x1E, 0xB4, 0x9A, 0xAA,
	0x88, 0x2C, 0x54, 0x7C, 0xD8, 0xF1, 0xB8, 0xB4,
	0xB0, 0x97, 0x86, 0xA8, 0x31, 0x9B, 0x06, 0x99,
	0x07, 0xAB, 0x97, 0x28, 0x88, 0x9B, 0xF0, 0x0C,
	0x20, 0x14, 0x40, 0xB0, 0xB4, 0xB8, 0xF0, 0xA8,
	0x8A, 0x9A, 0x28, 0x50, 0x78, 0xB7, 0x9B, 0xA8,
	0x29, 0x51, 0x79, 0x24, 0x70, 0x59, 0x44, 0x69,
	0x38, 0x64, 0x48, 0x31, 0xF1, 0xBB, 0xAB, 0x88,
	0x00, 0x2C, 0x54, 0x7C, 0xF0, 0xB3, 0x8B, 0xB8,
	0xA8, 0x04, 0x28, 0x50, 0x78, 0xF1, 0xB0, 0x88,
	0xB4, 0x97, 0x26, 0xA8, 0x59, 0x98, 0xBB, 0xAB,
	0xB3, 0x8B, 0x02, 0x26, 0x46, 0x66, 0xB0, 0xB8,
	0xF0, 0x8A, 0x9C, 0xA8, 0x29, 0x51, 0x79, 0x8B,
	0x29, 0x51, 0x8A, 0x24, 0x70, 0x59, 0x8B, 0x20,
	0x58, 0x8A, 0x44, 0x69, 0x38, 0x8B, 0x39, 0x40,
	0x8A, 0x64, 0x48, 0x31, 0x8B, 0x30, 0x49, 0x88,
	0xF1, 0xAC, 0x00, 0x2C, 0x54, 0x7C, 0xF0, 0x8C,
	0xA8, 0x04, 0x28, 0x50, 0x78, 0xF1, 0x88, 0x97,
	0x26, 0xA8, 0x59, 0x98, 0xAC, 0x8C, 0x02, 0x26,
	0x46, 0x66, 0xF0, 0x89, 0x9C, 0xA8, 0x29, 0x51,
	0x79, 0x24, 0x70, 0x59, 0x44, 0x69, 0x38, 0x64,
	0x48, 0x31, 0xA9, 0x88, 0x09, 0x20, 0x59, 0x70,
	0xAB, 0x11, 0x38, 0x40, 0x69, 0xA8, 0x19, 0x31,
	0x48, 0x60, 0x8C, 0xA8, 0x3C, 0x41, 0x5C, 0x20,
	0x7C, 0x00, 0xF1, 0x87, 0x98, 0x19, 0x86, 0xA8,
	0x6E, 0x76, 0x7E, 0xA9, 0x99, 0x88, 0x2D, 0x55,
	0x7D, 0xD8, 0xF1, 0xB3, 0x8B, 0xB4, 0x97, 0xBB,
	/* bank 6: 0x0600 */
	0xAB, 0xF8, 0xF9, 0xB9, 0xA3, 0xDA, 0xC3, 0xC5,
	0xC7, 0xD9, 0x2D, 0x4D, 0x6D, 0xD8, 0xB0, 0x8C,
	0xB8, 0xAC, 0xF8, 0xF9, 0xA8, 0xDA, 0xC3, 0xC5,
	0xC7, 0xD9, 0x2D, 0x4D, 0x6D, 0xD8, 0xF3, 0xB9,
	0xAC, 0xDE, 0xD8, 0xB1, 0xB6, 0xB9, 0xF1, 0xA8,
	0xF8, 0xF3, 0xB9, 0xAA, 0xFA, 0xF9, 0xD1, 0xDA,
	0xF2, 0x8A, 0xCA, 0xF4, 0x0E, 0xF3, 0xB1, 0x87,
	0xDD, 0xC2, 0xC2, 0xF1, 0x8C, 0xC4, 0xDC, 0xF3,
	0xB9, 0xAC, 0xF8, 0xD8, 0xF2, 0xB2, 0xB6, 0xBA,
	0xAD, 0xFA, 0x8D, 0x9D, 0xAB, 0x39, 0xD9, 0xAD,
	0xDF, 0xF4, 0x13, 0xDD, 0xF2, 0xB1, 0x87, 0xB5,
	0x9A, 0x08, 0x08, 0xF1, 0xB1, 0x83, 0xC2, 0xC4,
	0xC6, 0xDC, 0xF3, 0xB9, 0xAC, 0xF8, 0xD8, 0xF3,
	0xB2, 0xB6, 0xBA, 0xAD, 0xF8, 0x8D, 0x9D, 0xAB,
	0x11, 0xD9, 0xAD, 0xDE, 0xF4, 0x13, 0xDD, 0xF2,
	0xB1, 0x87, 0xB5, 0x9A, 0x28, 0x28, 0xF1, 0xB0,
	0x88, 0xC2, 0xC4, 0xC6, 0xDC, 0xF3, 0xB9, 0xAC,
	0xF8, 0xD8, 0xF3, 0xB2, 0xB6, 0xBA, 0xAD, 0xFA,
	0x8D, 0x9D, 0xAB, 0x39, 0xD9, 0xAD, 0xDF, 0xF4,
	0x12, 0xDD, 0xF3, 0xB1, 0x87, 0xB5, 0x9A, 0x08,
	0xF2, 0xF2, 0x88, 0xC2, 0xC4, 0xC6, 0xDC, 0xF3,
	0xB9, 0xAC, 0xF8, 0xD8, 0xF2, 0xB2, 0xB6, 0xBA,
	0xAE, 0xF8, 0x8E, 0x9E, 0xAB, 0x11, 0xD9, 0xAE,
	0xDE, 0xF4, 0x12, 0xDD, 0xF3, 0xB1, 0x87, 0xB5,
	0x9A, 0x68, 0xF2, 0xB0, 0x80, 0xC0, 0xC8, 0xC2,
	0xDC, 0xF3, 0xB9, 0xAC, 0xF8, 0xD8, 0xF2, 0xB2,
	0xB6, 0xBA, 0xAE, 0xFA, 0x8E, 0x9E, 0xAB, 0x39,
	0xD9, 0xAE, 0xDF, 0xF4, 0x12, 0xDD, 0xF2, 0xB1,
	0x87, 0xB5, 0x9A, 0x68, 0xF2, 0xB0, 0x80, 0xC4,
	0xCC, 0xC6, 0xDC, 0xF3, 0xB9, 0xAC, 0xF8, 0xD8,
	0xF3, 0xB2, 0xB6, 0xBA, 0xAE, 0xF8, 0x8E, 0x9E,
	0xAB, 0x11, 0xD9, 0xAE, 0xDE, 0xF4, 0x12, 0xDD,
	/* bank 7: 0x0700 */
	0xF3, 0xB1, 0x87, 0xB5, 0x9A, 0x48, 0xF2, 0xB0,
	0x81, 0xC0, 0xC8, 0xC2, 0xDC, 0xF3, 0xB9, 0xAC,
	0xF8, 0xD8, 0xF3, 0xB2, 0xB6, 0xBA, 0xAE, 0xFA,
	0x8E, 0x9E, 0xAB, 0x39, 0xD9, 0xAE, 0xDF, 0xF4,
	0x12, 0xDD, 0xF2, 0xB1, 0x87, 0xB5, 0x9A, 0x48,
	0xF2, 0xB0, 0x81, 0xC4, 0xCC, 0xC6, 0xDC, 0xF3,
	0xB9, 0xAC, 0xF8, 0xD8, 0xF2, 0xB0, 0x88, 0xB9,
	0xA8, 0xC3, 0xC5, 0xC7, 0xB1, 0xB5, 0xB9, 0xF3,
	0xAC, 0xFA, 0xF9, 0xD1, 0xDA, 0xF4, 0x10, 0xD8,
	0xF3, 0xAC, 0xF8, 0xF9, 0xD1, 0xDA, 0xF1, 0xB9,
	0xAA, 0xDF, 0xF4, 0x1C, 0xD9, 0xF4, 0x1A, 0xD8,
	0xF3, 0xAC, 0xF8, 0xF9, 0xD1, 0xD9, 0xF4, 0x1D,
	0xD8, 0xF2, 0x8C, 0xAC, 0xF8, 0xF9, 0xD1, 0xD9,
	0xC2, 0xD8, 0xF2, 0xF9, 0xD9, 0xDE, 0xF4, 0x09,
	0x1D, 0x16, 0xDA, 0xF2, 0xDD, 0xC6, 0xDC, 0xF4,
	0x30, 0xF1, 0xB9, 0xAA, 0xDF, 0xD8, 0xF1, 0xAB,
	0xFA, 0x8B, 0x9B, 0xA3, 0x69, 0xD9, 0xF4, 0x07,
	0x06, 0xDA, 0xF1, 0xB9, 0xAB, 0xDF, 0xFE, 0xD8,
	0xF1, 0xBB, 0xB3, 0xB7, 0xAA, 0xF9, 0xDA, 0xFF,
	0xD9, 0x80, 0x9A, 0xAA, 0x28, 0xB4, 0x80, 0x98,
	0xA7, 0x20, 0xD8, 0xF1, 0xB3, 0xB7, 0xBB, 0x87,
	0xAA, 0xD0, 0xC1, 0xA7, 0x81, 0x97, 0x62, 0x93,
	0xF0, 0x71, 0x71, 0x60, 0x85, 0x94, 0x01, 0x29,
	0x51, 0x79, 0x90, 0xA5, 0xF1, 0x28, 0x4C, 0x6C,
	0x87, 0x0C, 0x95, 0x18, 0x85, 0x78, 0xA3, 0x83,
	0x90, 0x28, 0x4C, 0x6C, 0x8A, 0x6C, 0xF2, 0xB0,
	0xB4, 0xB8, 0x83, 0x93, 0xA5, 0x71, 0xDB, 0xF1,
	0x8C, 0x01, 0xA3, 0xC0, 0xD8, 0xF2, 0x83, 0xA5,
	0x71, 0xD9, 0xA3, 0xD0, 0xF8, 0xF1, 0x9C, 0xA5,
	0xDB, 0x21, 0x8C, 0xA3, 0xC1, 0xD8, 0xF2, 0x83,
	0xA5, 0xC7, 0xF9, 0xF1, 0x93, 0x25, 0xF2, 0xA5,
	0x95, 0x49, 0xD9, 0xF3, 0xA3, 0xD0, 0xDE, 0xF8,
	/* bank 8: 0x0800 */
	0xF1, 0x84, 0xA5, 0xD0, 0xDB, 0x55, 0xF3, 0xA3,
	0xD0, 0xDE, 0xD8, 0xF2, 0xA5, 0x83, 0x95, 0x49,
	0xDB, 0xF3, 0x8E, 0x93, 0x11, 0xF1, 0x85, 0x94,
	0xA5, 0x79, 0x9E, 0x83, 0xF3, 0x69, 0xA3, 0xD0,
	0xF8, 0xD8, 0xF2, 0xA5, 0x83, 0x95, 0x49, 0xD9,
	0xF3, 0xA3, 0xD0, 0xC5, 0xF2, 0xA3, 0xD0, 0xDE,
	0xF1, 0xA3, 0xDE, 0x87, 0xC5, 0xD8, 0xF3, 0x8E,
	0x93, 0xA5, 0x11, 0xDB, 0xF2, 0x8D, 0xB7, 0x92,
	0x31, 0xBB, 0xA2, 0xD0, 0xC2, 0xA8, 0xB3, 0x82,
	0xB4, 0x9D, 0x21, 0xB0, 0x8D, 0xB7, 0x92, 0x49,
	0xA2, 0xDF, 0xD8, 0xF3, 0xB4, 0x9E, 0xB0, 0x83,
	0xB8, 0xA5, 0x49, 0xDB, 0xF2, 0xB3, 0x82, 0x9D,
	0x41, 0x21, 0xB0, 0x84, 0xB7, 0x92, 0x09, 0xD9,
	0xB3, 0x82, 0xBB, 0xA8, 0xF1, 0xCA, 0x96, 0x88,
	0xA6, 0x00, 0xD8, 0xF3, 0xB7, 0x90, 0xB0, 0x83,
	0xB8, 0xA5, 0x49, 0xDB, 0xF2, 0xB3, 0x82, 0xB4,
	0x9D, 0x41, 0xB0, 0x8D, 0xBB, 0xA2, 0xD0, 0xC0,
	0xB3, 0x82, 0xB4, 0x9D, 0xA8, 0x21, 0xA2, 0xDF,
	0xD8, 0xF3, 0xBB, 0xB3, 0xB7, 0x90, 0xA2, 0x82,
	0x00, 0xF2, 0x10, 0xA8, 0x92, 0x19, 0x80, 0xA2,
	0xF2, 0xD9, 0x26, 0xF3, 0xA7, 0xD0, 0xDF, 0xD8,
	0xF1, 0xA8, 0x89, 0x95, 0x19, 0xA9, 0x80, 0xD9,
	0x38, 0xD8, 0xA8, 0x89, 0x39, 0xA9, 0x80, 0xDA,
	0x3C, 0xD8, 0xA8, 0x2E, 0x85, 0xF5, 0x75, 0xDA,
	0xFF, 0xD8, 0x71, 0x80, 0xA9, 0xDA, 0xF1, 0xFF,
	0xD8, 0xD8, 0xF1, 0xB2, 0xB7, 0xBA, 0x83, 0x99,
	0xA4, 0x09, 0xDA, 0xA3, 0xDF, 0xF9, 0xC7, 0xF4,
	0x0B, 0xD8, 0xF1, 0xA3, 0xFB, 0xF8, 0xDB, 0xFB,
	0xD9, 0xDE, 0xA3, 0xDF, 0xD8, 0xF1, 0xA3, 0xFA,
	0xF9, 0xBB, 0xA9, 0xD0, 0x84, 0xDA, 0xC2, 0xD9,
	0xC4, 0xD8, 0xB3, 0x82, 0xA7, 0xF3, 0xC1, 0xF2,
	0x80, 0xC2, 0xF1, 0x97, 0x86, 0x49, 0x2E, 0xA6,
	/* bank 9: 0x0900 */
	0xD0, 0x50, 0x96, 0x86, 0xA8, 0x75, 0xD9, 0x88,
	0xA2, 0xD0, 0xF3, 0xC4, 0xC7, 0xF1, 0xDA, 0x88,
	0x96, 0xA2, 0xD0, 0xF3, 0xC2, 0xC3, 0x82, 0xB4,
	0x94, 0x68, 0x68, 0xF1, 0xD8, 0x80, 0xB7, 0x90,
	0xA8, 0x0D, 0x89, 0x99, 0xA8, 0x10, 0x80, 0x98,
	0x21, 0xDA, 0x2E, 0xD8, 0x89, 0x99, 0xA8, 0x31,
	0x80, 0xDA, 0x2E, 0xD8, 0xA8, 0x82, 0x92, 0xF3,
	0x41, 0x80, 0xF1, 0xD9, 0x2E, 0xD8, 0xA8, 0x82,
	0xF3, 0x19, 0x80, 0xF1, 0xD9, 0x2E, 0xD8, 0x82,
	0xAC, 0xF3, 0xC0, 0xA2, 0x80, 0x22, 0xF1, 0xA9,
	0x22, 0x26, 0x98, 0xA8, 0x29, 0xDA, 0xAC, 0xDE,
	0xFF, 0xD8, 0xA2, 0xF2, 0xDE, 0xF1, 0xA9, 0xDF,
	0x97, 0x8C, 0xA8, 0xF3, 0x79, 0xDA, 0xF1, 0xF1,
	0xF1, 0xF1, 0xB1, 0x88, 0xB9, 0xAC, 0xD0, 0xC0,
	0xB3, 0xF3, 0xF3, 0xB9, 0xAA, 0xFA, 0xF1, 0xBB,
	0xAA, 0xD0, 0xF8, 0xF4, 0x10, 0xD8, 0xF3, 0xA7,
	0xD0, 0xFA, 0x97, 0x8C, 0xA8, 0x79, 0xDA, 0xF1,
	0x87, 0x9A, 0xAA, 0xD0, 0x70, 0xD8, 0xF2, 0x82,
	0x92, 0xA8, 0x31, 0x80, 0xA6, 0x96, 0xF1, 0xD9,
	0x00, 0xAC, 0x8C, 0x9C, 0x0C, 0x30, 0xAC, 0xDE,
	0xD0, 0xDE, 0xF1, 0xFF, 0xD8, 0x8C, 0x9C, 0xAC,
	0xD0, 0x10, 0xAC, 0xDE, 0x80, 0x92, 0xA2, 0xF2,
	0x4C, 0x82, 0xA8, 0xF1, 0xCA, 0xF2, 0x35, 0xF1,
	0x96, 0x88, 0xA6, 0xD9, 0x00, 0xD8, 0xFF
};

struct nvi_dmp nvi_dmp_mpu = {
	.fw				= dmp_fw_6515,
	.fw_len				= ARRAY_SIZE(dmp_fw_6515),
	.fw_crc32			= 0x972AAE92,
	.fw_mem_addr			= 0x20,
	.fw_start			= 0x0400,
	.dev_msk			= (1 << DEV_SM) | (1 << DEV_QTN),
	.en_msk				= (1 << DEV_SM) | (1 << DEV_QTN),
	.dd_n				= ARRAY_SIZE(nvi_dmp_devs),
	.dd				= nvi_dmp_devs,
	.ap				= nvi_dmp_ap,
	.ap_n				= ARRAY_SIZE(nvi_dmp_ap),
	.fn_rd				= &nvi_dmp_rd,
	.fn_clk_n			= &nvi_dmp_clk_n,
	.fn_init			= &nvi_dmp_init,
	.fn_en				= &nvi_dmp_en,
	.fn_dev_init			= &nvi_dd_init,
	.fn_dev_batch			= &nvi_dd_batch,
};
EXPORT_SYMBOL(nvi_dmp_mpu);

